package com.qishenyuan.competition.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Preconditions;
import com.qishenyuan.competition.common.PageUtil;
import com.qishenyuan.competition.constant.UserConstant;
import com.qishenyuan.competition.dao.UserDao;
import com.qishenyuan.competition.dto.CreateTopicReq;
import com.qishenyuan.competition.dto.TeamupReq;
import com.qishenyuan.competition.exception.BusinessErrorType;
import com.qishenyuan.competition.exception.BusinessException;
import com.qishenyuan.competition.model.Teamup;
import com.qishenyuan.competition.dao.TeamupDao;
import com.qishenyuan.competition.model.User;
import com.qishenyuan.competition.service.TeamupService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qishenyuan.competition.utils.AliOssUtil;
import com.qishenyuan.competition.vo.TeamUpBriefResp;
import com.qishenyuan.competition.vo.TeamUpDetailResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.qishenyuan.competition.vo.TeamUpBriefResp.buildVo;

/**
 * @author qishenyuan
 * @since 2025-03-02
 */
@Service
@Slf4j
public class TeamupServiceImpl extends ServiceImpl<TeamupDao, Teamup> implements TeamupService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void createTopic(String token, CreateTopicReq createTopicReq) {
        if(StringUtils.isBlank(token)){
            throw new BusinessException(BusinessErrorType.INVALID_USER_TOKEN);
        }
        String userStr = stringRedisTemplate.opsForValue().get(token);
        if (StringUtils.isBlank(userStr)) {
            throw new BusinessException(BusinessErrorType.INVALID_USER_TOKEN);
        }

        try{
            User user = objectMapper.readValue(userStr, User.class);
            String uidFromRedis = user.getUid();
            if (!createTopicReq.getUid().equals(uidFromRedis)||createTopicReq.getUid().equals(UserConstant.DEFAULT_UID)){
                throw new BusinessException(BusinessErrorType.INVALID_USER_TOKEN);
            }
            Teamup teamup = Teamup.buildModel(createTopicReq,user);
            int insert = baseMapper.insert(teamup);
            if (insert != 1) {
                throw new BusinessException(BusinessErrorType.CREATE_TOPIC_FAILED);
            }
        }catch (Exception e){
            if (e instanceof BusinessException) {
                throw (BusinessException) e;
            }
            log.error("check user token error, 【token】: {}", token, e);
            throw new BusinessException(BusinessErrorType.SYSTEM_ERROR);
        }
    }

    @Override
    public IPage<TeamUpBriefResp> getTeamupList(String token, TeamupReq teamupReq) {
        try {
            log.info("current pageQuery: {}", teamupReq.getPageQuery().toString());
            IPage<Teamup> iPage = PageUtil.toIPage(teamupReq.getPageQuery());
            QueryWrapper<Teamup> queryWrapper = new QueryWrapper<>();
            if (teamupReq.getType() != null) {
                queryWrapper.eq("type", teamupReq.getType());
            }
            if (teamupReq.getTag() != null) {
                queryWrapper.eq("tag", teamupReq.getTag());
            }
            if (StringUtils.isNotBlank(token)) {
                String userStr = stringRedisTemplate.opsForValue().get(token);
                Preconditions.checkNotNull(userStr, "userStr from redis is null, token: " + token);
                String schoolFromRedis = objectMapper.readValue(userStr, User.class).getSchool();
                queryWrapper.eq("school", schoolFromRedis);
            }
            queryWrapper.orderByDesc("create_time");
            IPage<Teamup> iPageResult = baseMapper.selectPage(iPage, queryWrapper);
            if (Objects.isNull(iPageResult.getRecords()) || iPageResult.getRecords().isEmpty()) {
                return iPageResult.convert(teamup -> buildVo(teamup, null));
            }

            List<String> uids = iPageResult.getRecords().stream().map(Teamup::getUid).collect(Collectors.toList());
            List<User> users = userDao.listByUids(uids);

            // key->uid, value->User
            Map<String, User> userMap = users.stream()
                    .collect(Collectors.toMap(User::getUid, u -> u, (u1, u2) -> u1));

            return iPageResult.convert(teamup -> {
                User user = userMap.get(teamup.getUid());
                return buildVo(teamup, user);
            });
        }catch (Exception e){
            if (e instanceof BusinessException) {
                throw (BusinessException) e;
            }
            log.error("check user token error, 【token】: {}", token, e);
            throw new BusinessException(BusinessErrorType.SYSTEM_ERROR);
        }

    }

    @Override
    public TeamUpDetailResp getTeamUpDetail(Integer id) {
        Teamup teamup = baseMapper.selectById(id);
        TeamUpDetailResp teamUpDetailResp = TeamUpDetailResp.buildVo(teamup);
        User user = userDao.selectByUid(teamup.getUid());
        teamUpDetailResp.setPublisher(user.getNickName());
        if (UserConstant.DEFAULT_AVATAR.equals(user.getAvatar())) {
            teamUpDetailResp.setAvatar(UserConstant.DEFAULT_AVATAR);
        }else {
            teamUpDetailResp.setAvatar(AliOssUtil.generatePreSignedUrl(user.getAvatar()));
        }
        return teamUpDetailResp;
    }

    @Override
    public List<TeamUpBriefResp> searchTeamUp(String key) {
        QueryWrapper<Teamup> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(key),"title",key);
        List<Teamup> teamupList = baseMapper.selectList(queryWrapper);
        if (Objects.isNull(teamupList)||teamupList.isEmpty()) {
            return teamupList.stream().map(teamup -> buildVo(teamup,null)).collect(Collectors.toList());
        }
        List<String> uids = teamupList.stream().map(Teamup::getUid).collect(Collectors.toList());
        List<User> users = userDao.listByUids(uids);

        // key->uid, value->User
        Map<String, User> userMap = users.stream()
                .collect(Collectors.toMap(User::getUid, u -> u, (u1, u2) -> u1));

        return teamupList.stream().map(teamup -> {
            User user = userMap.get(teamup.getUid());
            return buildVo(teamup, user);
        }).collect(Collectors.toList());
    }
}
